package com.ruoyi.gbase.util;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.gbase.domain.TProcExecStatus;
import com.ruoyi.gbase.service.ITProcExecStatusService;
import com.ruoyi.nsh.util.DateUtil;
import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.service.ISysJobService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 存储过程任务执行
 *
 * @author ys.yin
 * @since 2020-11-03
 *
 */
@Component
public class PROCUil {
	private static final Log logger = LogFactory.getLog(PROCUil.class);

	@Autowired
	private SJXFUtil sjxfUtil;

	@Autowired
	private ITProcExecStatusService itProcExecStatusService;

	@Autowired
	private ISysJobService iSysJobService;

	@Autowired
	private GbaseUtil gbaseUtil;

	/**
	 * 执行存储任务
	 *
	 * @param sysJob 定时任务对象
	 */
	public void executeProc(SysJob sysJob) {

		try {
			InetAddress addr = InetAddress.getLocalHost();
			if("32.202.51.181".equals(addr.getHostAddress())){
				logger.info("当前为本机运行，不做存储过程跑批操作！！！ IP:"+addr.getHostAddress());
				return ;
			}
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}

		//logger.info("开始进入存储过程执行逻辑 executeProc:"+sysJob.getProcname());
		//20201204更新   6个参数改为1 ，直接改为 jobid
		Long jobId = sysJob.getJobId();
		String procName = sysJob.getProcName();
		String jobName = sysJob.getJobName();
		String parentProcName = sysJob.getParentProcName();
		String currentDate = DateUtils.getdateYYYYMMDD();
		String checkTables = sysJob.getProcCheckTables();
		String procExecuteSQL = sysJob.getProcCallSql();
		String recyleFlag = sysJob.getRecyleFlag();

		boolean odsisrkok = false;     				//ods 表已经下发完毕
		boolean parentProcIsSuccess = false;		//父任务是否ok
		String parentProcNonExecuteSuccess = "";

		//先判断有没有父任务，直接执行
		if (parentProcName == null || parentProcName.trim().equals("")) {
			parentProcIsSuccess = true;
			//logger.info("当前任务【" + procName + "】没有父任务，直接执行");
		} else {
			// 1.判断父任务是否执行成功
			String[] parentProcs = parentProcName.trim().split("#");
			for (String eachParentProc : parentProcs) {
				if(eachParentProc.equals("")){
					continue;
				}
				SysJob job2 = iSysJobService.selectJobByName(eachParentProc);
				if(job2 != null){
					//这里错了，应该是检查 父存储过程的id,根据名称获取id
					parentProcIsSuccess = checkProcIsDone(currentDate, job2.getJobId());
					if (parentProcIsSuccess == false) {
						logger.info("当前任务【" + procName + "】父任务【"+parentProcName+"】没有执行，结束");
						parentProcNonExecuteSuccess = eachParentProc;
						return;
					}
				}
			}
		}

		if (parentProcIsSuccess) {
			// 2.检查ODS依赖表是否入库完成 要看是否入GBASE数据库的表
			if (checkTables == null || checkTables.trim().equals("")) {
				odsisrkok = true;
				logger.info("当前任务【" + procName + "】直接执行，不依赖ODS表");
			} else {
				boolean tmp = true;
				String[] schemaTbs = checkTables.split("#");
				for (String schemaTb : schemaTbs) {
					if(schemaTb.trim().equals("")){
						continue;
					}
					String[] starr = schemaTb.trim().split("\\.");
					tmp = tmp && sjxfUtil.checkOdsTbRkIsOk_Gbase(starr[0].toUpperCase(), starr[1]
					);

					if (tmp == false) {
						logger.info("当前任务【" + procName + "】依赖ODS表【" + schemaTb + "】未入库完成，等待入库成功后执行");
						break;
					}
				}
				odsisrkok = tmp;
			}
		} else {
			logger.info("当前任务【" + procName + "】的付任务【" + parentProcNonExecuteSuccess + "】未执行成功，等待执行成功后，处理任务【" + procName + "】");
			return;
		}
		// ODS依赖表检查完毕
		boolean proccanExec = false;
		if (odsisrkok) {
			// 3.检查当前任务是否执行完成
			int procStatus = getProcIsDo(currentDate, jobId);
			if (procStatus == -1) {
				// 任务还未执行过，初次执行
				logger.info("当前任务【" + procName + "】未执行，初次执行");
				proccanExec = true;
				// 插入任务
				initProcStatus(currentDate, jobId);
			} else if (procStatus == 0) {
				logger.info("当前任务【" + procName + "】正在执行，请等待执行结果");
				return;
			} else if (procStatus == 1&&!jobName.equals("PROC_SS")) {
					//logger.info("当前任务【" + procName + "】执行成功，无需重复执行");
					return;
			} else if (procStatus == 2||jobName.equals("PROC_SS")) {
				// 任务执行失败，继续重复执行
				if ("1".equals(recyleFlag)) {
					logger.info("当前任务【" + procName + "】执行失败,可以重复执行");
					// 更新任务，修改其他值
					TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
					tProcExecStatus1.setJobId(jobId);;
					tProcExecStatus1.setProcExecDt(currentDate);
					itProcExecStatusService.deleteTProcExecStatus(tProcExecStatus1);
					proccanExec = true;
					// 插入任务,再次执行任务
					initProcStatus(currentDate, jobId);
				} else {
					//logger.info("当前任务【" + procName + "】执行成功，无需重复执行");
					return;
				}
			} else {
				// 任务执行失败
				logger.info("当前任务【" + procName + "】执行失败，请核查原因后再执行，procStatus："+procStatus);
				return;
			}
		} else {
			logger.info("当前任务【" + procName + "】依赖ODS表未入库完成，等待入库成功后执行");
			return;
		}

		if (proccanExec) {


			// 执行存储过程
			String kjrq = DateUtil.addDay(currentDate, -1);
			String startDate = kjrq.substring(0, 4) + "0101";
			String endDate = kjrq;
			//默认参数  如果填写的  STARTDATE 就取跑批日期当年第一天
			String newCallSQL = procExecuteSQL.toUpperCase().replace(
					"${STARTDATE}", startDate).replace("${ENDDATE}", endDate)
					.replace("${KJRQ}", kjrq);
			if (newCallSQL.contains("${")) {
				logger.info("当前存储过程还有未定义参数，无法执行");

				TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
				tProcExecStatus1.setJobId(jobId);
				tProcExecStatus1.setProcExecDt(currentDate);
				tProcExecStatus1.setProcExecStatus(2);
				tProcExecStatus1.setRemark("当前存储过程还有未定义参数，无法执行");
				itProcExecStatusService.updateTProcExecStatus(tProcExecStatus1);

				logger.info("当前任务【" + procName + "】执行失败，请请找原因");
			} else {
				try {


					//20201214添加，这里判断如果有前置baen，需要先执行
					if (proccanExec) {
						if (sysJob.getBeforeTask() != null && !sysJob.getBeforeTask().isEmpty()) {
							String str = sysJob.getBeforeTask();
							//执行bean
							String beanname = str.split("\\.")[0];
							String methodName = str.split("\\.")[1];
							String eltDt = DateUtils.getdateYYYYMMDD();
							//E_NewJxgsFp
							EntityAnalyse.getOneObjectByID(beanname, methodName,eltDt);
						}
					}


					//执行存储过错得到 gbase上面执行了。
					gbaseUtil.connectGBase();
					//gbaseUtil.update(newCallSQL,null);
					//newCallSQL="{call jx.test(?,?,?,22222)}";
					logger.info("newCallSQL:" + newCallSQL );
					Map<String,String> result = gbaseUtil.callPro(newCallSQL);
					logger.info("存储过程"+procName+"-code:" + result.get("code"));
					logger.info("存储过程"+procName+"-stateno:" + result.get("stateno"));
					logger.info("存储过程"+procName+"-msg:" + result.get("msg"));
					logger.info("存储过程"+procName+"-step_name:" + result.get("step_name"));
					if(result.get("code").equals("0")){
						TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
						tProcExecStatus1.setJobId(jobId);
						tProcExecStatus1.setProcExecDt(currentDate);
						tProcExecStatus1.setProcExecStatus(1);
						tProcExecStatus1.setRemark("执行成功");
						itProcExecStatusService.updateTProcExecStatus(tProcExecStatus1);
						logger.info("当前任务【" + procName + "】执行成功");
					}else{
						TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
						tProcExecStatus1.setJobId(jobId);
						tProcExecStatus1.setProcExecDt(currentDate);
						tProcExecStatus1.setProcExecStatus(2);
						tProcExecStatus1.setRemark("执行失败：\n"+procName+"-code:" + result.get("code")+"-stateno:" + result.get("stateno")
								+"-msg:" + result.get("msg")+"-step_name:" + result.get("step_name"));
						itProcExecStatusService.updateTProcExecStatus(tProcExecStatus1);
						///增加短信提示 暂时方法屏蔽了
						PROCUil.doFailSendSMS(procName);
						logger.info("当前任务【" + procName + "】执行失败," +procName+"-code:" + result.get("code")+"-stateno:" + result.get("stateno")
								+"-msg:" + result.get("msg")+"-step_name:" + result.get("step_name"));
					}
				} catch (SQLException e) {
					TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
					tProcExecStatus1.setJobId(jobId);
					tProcExecStatus1.setProcExecDt(currentDate);
					tProcExecStatus1.setProcExecStatus(2);
					tProcExecStatus1.setRemark("执行失败：存储过程在数据库可能不存在    "+e.getMessage());
					itProcExecStatusService.updateTProcExecStatus(tProcExecStatus1);
					///增加短信提示 暂时方法屏蔽了
					PROCUil.doFailSendSMS(procName);
					logger.info("当前任务【" + procName + "】执行失败,存储过程在数据库可能不存在   " + e.getMessage());
				}catch (Exception e) {
					TProcExecStatus tProcExecStatus1 = new TProcExecStatus();
					tProcExecStatus1.setJobId(jobId);
					tProcExecStatus1.setProcExecDt(currentDate);
					tProcExecStatus1.setProcExecStatus(2);
					tProcExecStatus1.setRemark("执行失败：其他异常    "+e.getMessage() );
					itProcExecStatusService.updateTProcExecStatus(tProcExecStatus1);
					///增加短信提示 暂时方法屏蔽了
					PROCUil.doFailSendSMS(procName);
					logger.info("当前任务【" + procName + "】执行失败,其他异常    " + e.getMessage());
				}
			}
		}

	}

	/**
	 * 检查任务是否处理完成
	 *
	 * @param currentDate 当前日期
	 * @param jobId 任务ID
	 * @return
	 */
	public boolean checkProcIsDone(String currentDate,Long jobId) {
		// 1.判断父任务是否执行
		TProcExecStatus tProcExecStatus = new TProcExecStatus();
		tProcExecStatus.setJobId(jobId);
		tProcExecStatus.setProcExecDt(currentDate);
		tProcExecStatus.setProcExecStatus(1);
		//-1表示未执行 0表示正在执行，1表示执行成功，2表示执行失败
		List<TProcExecStatus> lists = itProcExecStatusService.selectTProcExecStatusList(tProcExecStatus);
		if (lists != null && lists.size()>0) {
		return true;
		} else {
			return false;
		}
	}

	/**
	 * 检查任务是否在处理(处理中，处理完)
	 *
	 * @param currentDate 当前日期
	 * @param jobId 存储过程名称
	 * @return
	 */
	public  int getProcIsDo(String currentDate,Long jobId) {
		// 1.判断父任务是否执行
		TProcExecStatus tProcExecStatus = new TProcExecStatus();
		tProcExecStatus.setJobId(jobId);
		tProcExecStatus.setProcExecDt(currentDate);
		//-1表示未执行 0表示正在执行，1表示执行成功，2表示执行失败
		List<TProcExecStatus> lists = itProcExecStatusService.selectTProcExecStatusList(tProcExecStatus);
		if (lists != null && lists.size()>0) {
			return lists.get(0).getProcExecStatus();
		} else {
			return -1;
		}

	}

	/**
	 * 初始化存储过程执行状态
	 *
	 * @param currentDate
	 * @param jobId
	 */
	public void initProcStatus(String currentDate, Long jobId) {
		TProcExecStatus tProcExecStatus = new TProcExecStatus();
		tProcExecStatus.setJobId(jobId);
		tProcExecStatus.setProcExecDt(currentDate);
		//如果重新执行   先删除当天有的数据
		itProcExecStatusService.deleteTProcExecStatus(tProcExecStatus);
		tProcExecStatus.setProcExecStatus(0);
		tProcExecStatus.setRemark("初始化成功，正在执行");
		//int result = itProcExecStatusService.insertTProcExecStatus(tProcExecStatus);

	}

	/**
	 * 更新存储过程执行状态
	 *
	 * @param currentDate
	 * @param jobId
	 * @param status
	 */
	public void updateProcStatus(String currentDate, Long jobId, int status, String remark) {
		TProcExecStatus tProcExecStatus = new TProcExecStatus();
		tProcExecStatus.setJobId(jobId);
		tProcExecStatus.setProcExecDt(currentDate);
		tProcExecStatus.setProcExecStatus(status);
		tProcExecStatus.setRemark(remark);
	}



	/**
	 * 执行任务失败，发送短信
	 * @param procname
	 */
	public static void doFailSendSMS(String procname){
	/*
		String querySQL = "select A.PROC_EXEC_DT,A.PROC_NAME,COALESCE(PROC_EXEC_STATUS,'') zxzt,B.REMARK sm,C.REMARK name,CREATEBY yh from yzbank.T_PROC_EXEC_SMS_TMP A left join yzbank.T_PROC_EXEC_STATUS B on A.PROC_EXEC_DT=B.PROC_EXEC_DT and A.PROC_NAME=B.PROC_NAME left join yzbank.T_PROC_CRON C on A.PROC_NAME=C.PROCNAME where A.PROC_EXEC_DT=to_char(current date,'yyyyMMdd') and COALESCE(PROC_EXEC_STATUS,'')<>'1' ";
		if(procname!=null&&!"".equals(procname)){
			querySQL=querySQL+" and C.PROCNAME='"+procname+"'";
		}
		List<Map<String, String>> lists = DBUtil.executeQuery( YZMainApp.yzbankDataSource, querySQL);
		if (lists == null || lists.size() == 0) {
			logger.info("所有任务执行成功");
		} else {
			for (Map<String, String> eachMap : lists) {
				String proc_name=eachMap.get("proc_name");
				String zxzt=eachMap.get("zxzt");
				String sm=eachMap.get("sm");
				String name=eachMap.get("name");
				String yh=eachMap.get("yh");
				if(zxzt==null||zxzt.trim().equals("")){
					sm="涉及的ODS入库表未下发完成";
				}
				String tel="";
				if(yh.equals("殷永生")){
					tel="13852532209";
				}
				if(yh.equals("赵小飞")){
					tel="18751475207";
				}
				String message="批处理程序:【"+proc_name+"】用途:【"+name+"】未执行完成；原因;【"+sm+"】,请及时处理。";

				try {
					DXPTDBTool.execute("", tel, message, "103060500005");
				} catch (Exception e) {
				}

			}
		}
		*/


	}


	public static void main(String[] args) {
		String callSQL = "call yzbank.PROC_FIN_CALJSRJ4JXKHXT('${startDate}','${endDate}')";
		System.out.println(callSQL.toUpperCase().replace("${STARTDATE}",
				"20170101").replace("${ENDDATE}", "20171206"));
	}
}
